/******************************************************************************
 * Product: Adempiere ERP & CRM Smart Business Solution                       *
 * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved.                *
 * This program is free software; you can redistribute it and/or modify it    *
 * under the terms version 2 of the GNU General Public License as published   *
 * by the Free Software Foundation. This program is distributed in the hope   *
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.           *
 * See the GNU General Public License for more details.                       *
 * You should have received a copy of the GNU General Public License along    *
 * with this program; if not, write to the Free Software Foundation, Inc.,    *
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.                     *
 * For the text or an alternative of this public license, you may reach us    *
 * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA        *
 * or via info@compiere.org or http://www.compiere.org/license.html           *
 *****************************************************************************/
package org.compiere.acct;

import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Level;

import org.apache.ecs.xhtml.li;
import org.apache.xerces.impl.dv.ValidatedInfo;
import org.compiere.model.I_C_ValidCombination;
import org.compiere.model.MAccount;
import org.compiere.model.MAccountCombination;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MClientInfo;
import org.compiere.model.MConversionRate;
import org.compiere.model.MCostDetail;
import org.compiere.model.MCurrency;
import org.compiere.model.MDepreciationWorkfile;
import org.compiere.model.MDocType;
import org.compiere.model.MFI_C_PaymentLine;
import org.compiere.model.MFactAcct;
import org.compiere.model.MJournal;
import org.compiere.model.MJournalBatch;
import org.compiere.model.MJournalLine;
import org.compiere.model.MTable;
import org.compiere.model.Mhrmcharge;
import org.compiere.model.Mhrmemployee;
import org.compiere.model.Mhrmlimitholiday;
import org.compiere.model.Mhrmorder;
import org.compiere.model.Mhrmpayment;
import org.compiere.model.MInvoiceLine;
import org.compiere.model.MLandedCostAllocation;
import org.compiere.model.MTax;
import org.compiere.model.Mhrmpaymentlist;
import org.compiere.model.Mhrmreserve;
import org.compiere.model.Mhrmreview;
import org.compiere.model.Mhrmreviewline;
import org.compiere.model.Mhrmvacation;
import org.compiere.model.ProductCost;
import org.compiere.model.X_A_Asset;
import org.compiere.model.X_A_Asset_Addition;
import org.compiere.model.X_hrm_charge;
import org.compiere.model.X_hrm_order;
import org.compiere.model.X_hrm_reviewline;
import org.compiere.util.DB;
import org.compiere.util.Env;

import extend.org.compiere.hrm.Reserve;

/**
 *  Post Invoice Documents.
 *  <pre>
 *  Table:              C_Invoice (318)
 *  Document Types:     ARI, ARC, ARF, API, APC
 *  </pre>
 *  @author Jorg Janke
 *  @author Armen Rizal, Goodwill Consulting
 *  	<li>BF: 2797257	Landed Cost Detail is not using allocation qty
 *  
 *  @version  $Id: Doc_Invoice.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $
 */
public class Doc_hrmreview extends Doc
{
	/**
	 *  Constructor
	 * 	@param ass accounting schemata
	 * 	@param rs record
	 * 	@param trxName trx
	 */
	public Doc_hrmreview(MAcctSchema[] ass, ResultSet rs, String trxName)
	{
		super (ass, Mhrmreview.class, rs, null, trxName);
	}	//	Doc_hrmreview

	/** Contained Optional Tax Lines    */
	private DocTax[]        m_taxes = null;
	/** Currency Precision				*/
	private int				m_precision = -1;
//	/** All lines are Service			*/
//	private boolean			m_allLinesService = true;
//	/** All lines are product item		*/
//	private boolean			m_allLinesItem = true;

	/**
	 *  Load Specific Document Details
	 *  @return error message or null
	 */
	protected String loadDocumentDetails ()
	{
		
		Mhrmreview hr = (Mhrmreview)getPO();
		setDateDoc(hr.getDateAcct());
		p_lines = loadLines(hr);
		return null;
	}   //  loadDocumentDetails	

	/**
	 *	Load Invoice Taxes
	 *  @return DocTax Array
	 */
	private DocTax[] loadTaxes()
	{
		ArrayList<DocTax> list = new ArrayList<DocTax>();
		String sql = "SELECT it.C_Tax_ID, t.Name, t.Rate, it.TaxBaseAmt, it.TaxAmt, t.IsSalesTax "
			+ "FROM C_Tax t, C_InvoiceTax it "
			+ "WHERE t.C_Tax_ID=it.C_Tax_ID AND it.C_Invoice_ID=?";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try
		{
			pstmt = DB.prepareStatement(sql, getTrxName());
			pstmt.setInt(1, get_ID());
			rs = pstmt.executeQuery();
			//
			while (rs.next())
			{
				int C_Tax_ID = rs.getInt(1);
				String name = rs.getString(2);
				BigDecimal rate = rs.getBigDecimal(3);
				BigDecimal taxBaseAmt = rs.getBigDecimal(4);
				BigDecimal amount = rs.getBigDecimal(5);
				boolean salesTax = "Y".equals(rs.getString(6));
				//
				DocTax taxLine = new DocTax(C_Tax_ID, name, rate, 
					taxBaseAmt, amount, salesTax);
				log.fine(taxLine.toString());
				list.add(taxLine);
			}
		}
		catch (SQLException e)
		{
			log.log(Level.SEVERE, sql, e);
			return null;
		}
		finally {
			DB.close(rs, pstmt);
			rs = null; pstmt = null;
		}

		//	Return Array
		DocTax[] tl = new DocTax[list.size()];
		list.toArray(tl);
		return tl;
	}//	loadTaxes

	/**
	 *	Load Invoice Line
	 *	@param invoice invoice
	 *  @return DocLine Array
	 */
	private DocLine[] loadLines (Mhrmreview invoice)
	{
		ArrayList<DocLine> list = new ArrayList<DocLine>();
//		//
//		MInvoiceLine[] lines = invoice.getLines(false);
//		for (int i = 0; i < lines.length; i++)
//		{
//			MInvoiceLine line = lines[i];
//			if (line.isDescription())
//				continue;
//			DocLine docLine = new DocLine(line, this);
//			//	Qty
//			BigDecimal Qty = line.getQtyInvoiced();
//			boolean cm = getDocumentType().equals(DOCTYPE_ARCredit) 
//				|| getDocumentType().equals(DOCTYPE_APCredit);
//			docLine.setQty(cm ? Qty.negate() : Qty, invoice.isSOTrx());
//			//
//			BigDecimal LineNetAmt = line.getLineNetAmt();
//			BigDecimal PriceList = line.getPriceList();
//			int C_Tax_ID = docLine.getC_Tax_ID();
//			//	Correct included Tax
//			if (isTaxIncluded() && C_Tax_ID != 0 && !getDocumentType().equals(DOCTYPE_AdvanceStatement))
//			{
//				MTax tax = MTax.get(getCtx(), C_Tax_ID);
//				if (!tax.isZeroTax())
//				{
//					BigDecimal LineNetAmtTax = tax.calculateTax(LineNetAmt, true, getStdPrecision());
//					log.fine("LineNetAmt=" + LineNetAmt + " - Tax=" + LineNetAmtTax);
//					LineNetAmt = LineNetAmt.subtract(LineNetAmtTax);
//					for (int t = 0; t < m_taxes.length; t++)
//					{
//						if (m_taxes[t].getC_Tax_ID() == C_Tax_ID)
//						{
//							m_taxes[t].addIncludedTax(LineNetAmtTax);
//							break;
//						}
//					}
//					BigDecimal PriceListTax = tax.calculateTax(PriceList, true, getStdPrecision());
//					PriceList = PriceList.subtract(PriceListTax);
//				}
//			}	//	correct included Tax
//			
//			docLine.setAmount (LineNetAmt, PriceList, Qty);	//	qty for discount calc
//			if (docLine.isItem())
//				m_allLinesService = false;
//			else
//				m_allLinesItem = false;
//			//
//			log.fine(docLine.toString());
//			list.add(docLine);
//		}
//		
//		//	Convert to Array
		DocLine[] dls = new DocLine[list.size()];
		list.toArray(dls);
//
//		//	Included Tax - make sure that no difference
//		if (isTaxIncluded())
//		{
//			for (int i = 0; i < m_taxes.length; i++)
//			{
//				if (m_taxes[i].isIncludedTaxDifference())
//				{
//					BigDecimal diff = m_taxes[i].getIncludedTaxDifference(); 
//					for (int j = 0; j < dls.length; j++)
//					{
//						if (dls[j].getC_Tax_ID() == m_taxes[i].getC_Tax_ID())
//						{
//							dls[j].setLineNetAmtDifference(diff);
//							break;
//						}
//					}	//	for all lines
//				}	//	tax difference
//			}	//	for all taxes
//		}	//	Included Tax difference
//		
		//	Return Array
		return dls;
	}	//	loadLines

	/**
	 * 	Get Currency Precision
	 *	@return precision
	 */
	private int getStdPrecision()
	{
		if (m_precision == -1)
			m_precision = MCurrency.getStdPrecision(getCtx(), getC_Currency_ID());
		return m_precision;
	}	//	getPrecision

	
	/**************************************************************************
	 *  Get Source Currency Balance - subtracts line and tax amounts from total - no rounding
	 *  @return positive amount, if total invoice is bigger than lines
	 */
	public BigDecimal getBalance()
	{
		BigDecimal retValue = Env.ZERO;
//		StringBuffer sb = new StringBuffer (" [");
//		//  Total
//		retValue = retValue.add(getAmount(Doc.AMTTYPE_Gross));
//		sb.append(getAmount(Doc.AMTTYPE_Gross));
//		//  - Header Charge
//		retValue = retValue.subtract(getAmount(Doc.AMTTYPE_Charge));
//		sb.append("-").append(getAmount(Doc.AMTTYPE_Charge));
//		//  - Tax
//		for (int i = 0; i < m_taxes.length; i++)
//		{
//			retValue = retValue.subtract(m_taxes[i].getAmount());
//			sb.append("-").append(m_taxes[i].getAmount());
//		}
//		//  - Lines
//		for (int i = 0; i < p_lines.length; i++)
//		{
//			retValue = retValue.subtract(p_lines[i].getAmtSource());
//			sb.append("-").append(p_lines[i].getAmtSource());
//		}
//		sb.append("]");
//		//
//		log.fine(toString() + " Balance=" + retValue + sb.toString());
		return retValue;
	}   //  getBalance

	/**
	 *  Create Facts (the accounting logic) for
	 *  ARI, ARC, ARF, API, APC.
	 *  <pre>
	 *  ARI, ARF
	 *      Receivables     DR
	 *      Charge                  CR
	 *      TaxDue                  CR
	 *      Revenue                 CR
	 *
	 *  ARC
	 *      Receivables             CR
	 *      Charge          DR
	 *      TaxDue          DR
	 *      Revenue         RR
	 *
	 *  API
	 *      Payables                CR
	 *      Charge          DR
	 *      TaxCredit       DR
	 *      Expense         DR
	 *
	 *  APC
	 *      Payables        DR
	 *      Charge                  CR
	 *      TaxCredit               CR
	 *      Expense                 CR
	 *  </pre>
	 *  @param as accounting schema
	 *  @return Fact
	 */
	public ArrayList<Fact> createFacts (MAcctSchema as)
	{
		//
		ArrayList<Fact> facts = new ArrayList<Fact>();
		//  create Fact Header
		
		//MAccount acct = null;
		MAccount acct7210 = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as); //7210
		MAccount acct3120 = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
		MAccount acct3150 = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
		MAccount acct3210 = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
		MAccount acct3220 = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
		MAccount acct3350 = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
		MAccount acct3430 = getAccount(Doc.ACCTTYPE_HRMREZERV, as); //3430	
		
		Fact fact = new Fact(this, as, Fact.POST_Actual); 
		Mhrmreview rev = new Mhrmreview(getCtx(), get_ID(), getTrxName());
		
		if (rev.haveReversal()) {
			facts = makeCorrectFact(rev, as);
			return facts;
		}
		
		Mhrmreviewline[] lines = rev.getLinesReview();		
		
		Mhrmorder order = new Mhrmorder(getCtx(), rev.gethrm_order_ID(), getTrxName());
		Mhrmemployee[] emp = order.getLinesEmployee();		
//		Integer BPHeader = emp[0].getC_BPartner_ID();
//		Integer BPHeader = getC_BPartner_ID();
		
		FactLine fl = null;	    		
    	setDateAcct(rev.getDateFrom());
		DocLine DocLine = null;
		X_hrm_reviewline charge = null;
		int C_Charge_ID = 0;
		
		if (X_hrm_order.HRM_COMPENSATIONTYPE_Profit.equals(rev.gethrm_compensationtype())){			
			
			for(int i = 0; i < lines.length; i++ ){
				
				Mhrmreviewline line = lines[i];
				Integer bp =  line.getC_BPartner_ID();
				
				BigDecimal amountCharge = line.gethrm_total();
				BigDecimal amountCNalog = line.gethrm_CNalog();
				BigDecimal amountCOtch = line.gethrm_COtch();
				BigDecimal amountIPN = line.gethrm_IPN();
				BigDecimal amountOPV = line.gethrm_OPV();			
				
				/// IPN
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountIPN, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
				fl = fact.createLine(null, acct3120, getC_Currency_ID(), null, amountIPN);
				
				/// OPV
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountOPV, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
				fl = fact.createLine(null, acct3220, getC_Currency_ID(), null, amountOPV);
				
		    	// detect c_charge_id and fill hrm_paymentline
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_Payment, rev.getDateFrom());
				charge = Mhrmreviewline.getline(rev.gethrm_review_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_reviewline(getCtx(), 0, null);
				}
		    	charge.sethrm_review_ID(rev.gethrm_review_ID());
		    	charge.sethrm_review_line_ID(line.gethrm_review_line_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(amountCharge);
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
				
		    	setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), amountCharge, null);
				
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(DocLine, acct3350, getC_Currency_ID(), null, amountCharge);				
				
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_CNalog, rev.getDateFrom());
				charge = Mhrmreviewline.getline(rev.gethrm_review_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_reviewline(getCtx(), 0, null);
				}
		    	charge.sethrm_review_ID(rev.gethrm_review_ID());
		    	charge.sethrm_review_line_ID(line.gethrm_review_line_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(amountCNalog);
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
								
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), amountCNalog, null);					
	
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
				fl = fact.createLine(DocLine, acct3150, getC_Currency_ID(), null, amountCNalog);
				
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_COtche, rev.getDateFrom());
				charge = Mhrmreviewline.getline(rev.gethrm_review_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_reviewline(getCtx(), 0, null);
				}
		    	charge.sethrm_review_ID(rev.gethrm_review_ID());
		    	charge.sethrm_review_line_ID(line.gethrm_review_line_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(amountCOtch);
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
				
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), amountCOtch, null);					
	
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
				fl = fact.createLine(DocLine, acct3210, getC_Currency_ID(), null, amountCOtch);
			}		
			
		}else if (X_hrm_order.HRM_ORDERTYPE_Review.equals(order.gethrm_ordertype())){		
			
		for(int i = 0; i < lines.length; i++ ){
		//	Mhrmlimitholiday holiDaylimit = null;
				Mhrmreviewline line = lines[i];
				Integer bp =  line.getC_BPartner_ID();
				
				BigDecimal amountCharge = line.gethrm_total();
				BigDecimal amountCNalog = line.gethrm_CNalog();
//				BigDecimal amountCOtch = line.gethrm_COtch();
				BigDecimal amountIPN = line.gethrm_IPN();
				BigDecimal amountOPV = line.gethrm_OPV();
//				
//				Reserve reserve = new Reserve(bp, rev.getDateFrom(),Mhrmreserve.RESERVE_VACATION, acct3430.getAccount_ID());			
//				BigDecimal reserveCharge = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_CHARGE);
//				BigDecimal reserveCNalog = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_CNALOG);
//				BigDecimal reserveCOtch = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_COTCH);
				
		    	setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
				fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCharge, null);
				fl.setLine_ID(rev.getReviewLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE).gethrm_reviewline_ID());
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, amountCharge);
				
				/// IPN
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountIPN, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
				fl = fact.createLine(null, acct3120, getC_Currency_ID(), null, amountIPN);
				
				/// OPV
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountOPV, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
				fl = fact.createLine(null, acct3220, getC_Currency_ID(), null, amountOPV);
				
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
				fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCNalog, null);
				fl.setLine_ID(rev.getReviewLine(Mhrmreserve.RESERVE_SECTIONAL_CNALOG).gethrm_reviewline_ID());

				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
				fl = fact.createLine(null, acct3150, getC_Currency_ID(), null, amountCNalog);
				
//				setC_BPartner_ID(bp);
//				//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
//				fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCOtch, null);				
//
//				setC_BPartner_ID(bp);
//				//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
//				fl = fact.createLine(null, acct3210, getC_Currency_ID(), null, amountCOtch);				
	    	
			}
			
		}else if(X_hrm_order.HRM_ORDERTYPE_Dismissal.equals(order.gethrm_ordertype())){
			
			for(int i = 0; i < lines.length; i++ ){		
			
				Mhrmreviewline line = lines[i];
				Integer bp =  line.getC_BPartner_ID();				
			
				BigDecimal amountCharge = line.gethrm_total();			
				BigDecimal amountIPN = line.gethrm_IPN();				
				
				Reserve reserve = new Reserve(bp, rev.getDateFrom(),Mhrmreserve.RESERVE_VACATION, acct3430.getAccount_ID());			
				BigDecimal reserveCharge = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_CHARGE);
				BigDecimal reserveCNalog = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_CNALOG);
				BigDecimal reserveCOtch = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_COTCH);			
							
	    		BigDecimal diff = new BigDecimal(0);    		
		    	
		    	// check reserve sum not zero
		    	if (reserveCharge.compareTo(new BigDecimal(0)) == 1){
		    		
		    		diff = amountCharge.add(reserveCharge.negate());
		    		
		    		if (reserveCharge.compareTo(amountCharge) == 0){
		    			
		    			setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
						fl = fact.createLine(null, acct3430, getC_Currency_ID(), reserveCharge, null);
						fl.setLine_ID(rev.getReviewLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE).gethrm_reviewline_ID());
						
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
						fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, reserveCharge);
						
		    		}else if(reserveCharge.compareTo(amountCharge) == 1){
		    			
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMRESERV, as);	//3430				
						fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCharge, null);
						fl.setLine_ID(rev.getReviewLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE).gethrm_reviewline_ID());
						
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
						fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, amountCharge);
						
						// detect c_charge_id and fill hrm_paymentline
						C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_Payment, rev.getDateFrom());
						charge = Mhrmreviewline.getline(rev.gethrm_review_ID(), bp, C_Charge_ID);
						if (charge == null || charge.get_ID() == 0){
							charge = new X_hrm_reviewline(getCtx(), 0, null);
						}
				    	charge.sethrm_review_ID(rev.gethrm_review_ID());
				    	charge.sethrm_review_line_ID(line.gethrm_review_line_ID());				    	
				    	charge.setC_BPartner_ID(bp);
				    	charge.setC_Charge_ID(C_Charge_ID);
				    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
				    	charge.sethrm_amount(diff.negate());
				    	charge.sethrm_reserve_ID(0);
				    	charge.sethrm_reservesectional_ID(0);
				    	charge.saveEx();
				    	DocLine = new DocLine(charge, this);
				    	
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMRESERV, as);	//3430				
						fl = fact.createLine(DocLine, acct3430, getC_Currency_ID(), diff.negate(), null);
						fl.setLine_ID(rev.getReviewLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE).gethrm_reviewline_ID());
						
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
						fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), null, diff.negate());
			    		
			    	}else if(reserveCharge.compareTo(amountCharge) == -1){
			    		
			    		setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
						fl = fact.createLine(null, acct3430, getC_Currency_ID(), reserveCharge, null);
						fl.setLine_ID(rev.getReviewLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE).gethrm_reviewline_ID());
						
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
						fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, reserveCharge);
						
						// detect c_charge_id and fill hrm_paymentline
						C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_Payment, rev.getDateFrom());
						charge = Mhrmreviewline.getline(rev.gethrm_review_ID(), bp, C_Charge_ID);
						if (charge == null || charge.get_ID() == 0){
							charge = new X_hrm_reviewline(getCtx(), 0, null);
						}
				    	charge.sethrm_review_ID(rev.gethrm_review_ID());
				    	charge.sethrm_review_line_ID(line.gethrm_review_line_ID());
				    	charge.setC_BPartner_ID(bp);
				    	charge.setC_Charge_ID(C_Charge_ID);
				    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
				    	charge.sethrm_amount(diff);
				    	charge.sethrm_reserve_ID(0);
				    	charge.sethrm_reservesectional_ID(0);
				    	charge.saveEx();
				    	DocLine = new DocLine(charge, this);
				    	
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
						fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), diff, null);
						
						setC_BPartner_ID(bp);
						//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
						fl = fact.createLine(DocLine, acct3350, getC_Currency_ID(), null, diff);						
			    	}
		    		
		    	}else{
		    		
		    		// detect c_charge_id and fill hrm_paymentline
					C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_Payment, rev.getDateFrom());
					charge = Mhrmreviewline.getline(rev.gethrm_review_ID(), bp, C_Charge_ID);
					if (charge == null || charge.get_ID() == 0){
						charge = new X_hrm_reviewline(getCtx(), 0, null);
					}
			    	charge.sethrm_review_ID(rev.gethrm_review_ID());
			    	charge.sethrm_review_line_ID(line.gethrm_review_line_ID());
			    	charge.setC_BPartner_ID(bp);
			    	charge.setC_Charge_ID(C_Charge_ID);
			    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			    	charge.sethrm_amount(amountCharge);
			    	charge.sethrm_reserve_ID(0);
			    	charge.sethrm_reservesectional_ID(0);
			    	charge.saveEx();
			    	DocLine = new DocLine(charge, this);
			    	
		    		setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
					fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), amountCharge, null);
					
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
					fl = fact.createLine(DocLine, acct3350, getC_Currency_ID(), null, amountCharge);		    		
		    	}
		    			    	
				/// IPN
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountIPN, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
				fl = fact.createLine(null, acct3120, getC_Currency_ID(), null, amountIPN);
				
				/** Calculate CNalog */				
				if (reserveCNalog.compareTo(new BigDecimal(0)) == 1 ){
					
					// detect c_charge_id and fill hrm_paymentline
					C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_CNalog, rev.getDateFrom());
					charge = Mhrmreviewline.getline(rev.gethrm_review_ID(), bp, C_Charge_ID);
					if (charge == null || charge.get_ID() == 0){
						charge = new X_hrm_reviewline(getCtx(), 0, null);
					}
			    	charge.sethrm_review_ID(rev.gethrm_review_ID());
			    	charge.sethrm_review_line_ID(line.gethrm_review_line_ID());
			    	charge.setC_BPartner_ID(bp);
			    	charge.setC_Charge_ID(C_Charge_ID);
			    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			    	charge.sethrm_amount(reserveCNalog.negate());
			    	charge.sethrm_reserve_ID(0);
			    	charge.sethrm_reservesectional_ID(0);
			    	charge.saveEx();
			    	DocLine = new DocLine(charge, this);
				
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
					fl = fact.createLine(DocLine, acct3430, getC_Currency_ID(), null, reserveCNalog.negate());
					fl.setLine_ID(rev.getReviewLine(Mhrmreserve.RESERVE_SECTIONAL_CNALOG).gethrm_reviewline_ID());
							
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
					fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), reserveCNalog.negate(), null);				
				}
		    			    	
		    	/** Calculate COtch */		    	
				if (reserveCOtch.compareTo(new BigDecimal(0)) == 1 ){
					
					// detect c_charge_id and fill hrm_paymentline
					C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_COtche, rev.getDateFrom());
					charge = Mhrmreviewline.getline(rev.gethrm_review_ID(), bp, C_Charge_ID);
					if (charge == null || charge.get_ID() == 0){
						charge = new X_hrm_reviewline(getCtx(), 0, null);
					}
			    	charge.sethrm_review_ID(rev.gethrm_review_ID());
			    	charge.sethrm_review_line_ID(line.gethrm_review_line_ID());
			    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			    	charge.sethrm_amount(reserveCOtch.negate());
			    	charge.sethrm_reserve_ID(0);
			    	charge.sethrm_reservesectional_ID(0);
			    	DocLine = new DocLine(charge, this);
			    	
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
					fl = fact.createLine(DocLine, acct3430, getC_Currency_ID(), null, reserveCOtch.negate());
					fl.setLine_ID(rev.getReviewLine(Mhrmreserve.RESERVE_SECTIONAL_COTCH).gethrm_reviewline_ID());
							
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
					fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), reserveCOtch.negate(), null);					
				}		
			}			
		}		

		facts.add(fact);
		return facts;
	}   //  createFact

	public int checkValidCombination(int account_ID, int C_BPartner_ID){
		
		String sql = " select c_validcombination_id from adempiere.c_validcombination where account_id = " + account_ID + " and c_bpartner_id = " + C_BPartner_ID;
		
		int AccountValid = 0;
		
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		try{
			pstmt = DB.prepareStatement(sql, null);
			rs = pstmt.executeQuery();
			while (rs.next()) {
				AccountValid = rs.getInt(1);
			}
		}catch(SQLException e){
			log.log(Level.WARNING, e.getLocalizedMessage());
		}
		
		return AccountValid;
		
	}
	
	
	/**
	 * 	Create Fact Cash Based (i.e. only revenue/expense)
	 *	@param as accounting schema
	 *	@param fact fact to add lines to
	 *	@param multiplier source amount multiplier
	 *	@return accounted amount
	 */
	public BigDecimal createFactCash (MAcctSchema as, Fact fact, BigDecimal multiplier)
	{
		boolean creditMemo = getDocumentType().equals(DOCTYPE_ARCredit)
			|| getDocumentType().equals(DOCTYPE_APCredit);
		boolean payables = getDocumentType().equals(DOCTYPE_APInvoice)
			|| getDocumentType().equals(DOCTYPE_APCredit);
		BigDecimal acctAmt = Env.ZERO;
		FactLine fl = null;
		//	Revenue/Cost
		for (int i = 0; i < p_lines.length; i++)
		{
			DocLine line = p_lines[i];
			boolean landedCost = false;
			if  (payables)
				landedCost = landedCost(as, fact, line, false);
			if (landedCost && as.isExplicitCostAdjustment())
			{
				fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
					getC_Currency_ID(), null, line.getAmtSource());
				//
				fl = fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
					getC_Currency_ID(), line.getAmtSource(), null);
				String desc = line.getDescription();
				if (desc == null)
					desc = "100%";
				else
					desc += " 100%";
				fl.setDescription(desc);
			}
			if (!landedCost)
			{
				MAccount acct = line.getAccount(
					payables ? ProductCost.ACCTTYPE_P_Expense : ProductCost.ACCTTYPE_P_Revenue, as);
				if (payables)
				{
					//	if Fixed Asset
					if (line.isItem())
						acct = line.getAccount (ProductCost.ACCTTYPE_P_InventoryClearing, as);
				}
				BigDecimal amt = line.getAmtSource().multiply(multiplier);
				BigDecimal amt2 = null;
				if (creditMemo)
				{
					amt2 = amt;
					amt = null;
				}
				if (payables)	//	Vendor = DR
					fl = fact.createLine (line, acct,
						getC_Currency_ID(), amt, amt2);
				else			//	Customer = CR
					fl = fact.createLine (line, acct,
						getC_Currency_ID(), amt2, amt);
				if (fl != null)
					acctAmt = acctAmt.add(fl.getAcctBalance());
			}
		}
		//  Tax
		for (int i = 0; i < m_taxes.length; i++)
		{
			BigDecimal amt = m_taxes[i].getAmount();
			BigDecimal amt2 = null;
			if (creditMemo)
			{
				amt2 = amt;
				amt = null;
			}
			FactLine tl = null;
			if (payables)
				tl = fact.createLine (null, m_taxes[i].getAccount(m_taxes[i].getAPTaxType(), as),
					getC_Currency_ID(), amt, amt2);
			else
				tl = fact.createLine (null, m_taxes[i].getAccount(DocTax.ACCTTYPE_TaxDue, as),
					getC_Currency_ID(), amt2, amt);
			if (tl != null)
				tl.setC_Tax_ID(m_taxes[i].getC_Tax_ID());
		}
		//  Set Locations
		FactLine[] fLines = fact.getLines();
		for (int i = 0; i < fLines.length; i++)
		{
			if (fLines[i] != null)
			{
				if (payables)
				{
					fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), true);  //  from Loc
					fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), false);    //  to Loc
				}
				else
				{
					fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), true);    //  from Loc
					fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), false);  //  to Loc
				}
			}
		}
		return acctAmt;
	}	//	createFactCash
	
	
	/**
	 * 	Create Landed Cost accounting & Cost lines
	 *	@param as accounting schema
	 *	@param fact fact
	 *	@param line document line
	 *	@param dr DR entry (normal api)
	 *	@return true if landed costs were created
	 */
	private boolean landedCost (MAcctSchema as, Fact fact, DocLine line, boolean dr) 
	{
		int C_InvoiceLine_ID = line.get_ID();
		MLandedCostAllocation[] lcas = MLandedCostAllocation.getOfInvoiceLine(
			getCtx(), C_InvoiceLine_ID, getTrxName());
		if (lcas.length == 0)
			return false;
		
		//	Calculate Total Base
		double totalBase = 0;
		for (int i = 0; i < lcas.length; i++)
			totalBase += lcas[i].getBase().doubleValue();
		
		//	Create New
		MInvoiceLine il = new MInvoiceLine (getCtx(), C_InvoiceLine_ID, getTrxName());
		for (int i = 0; i < lcas.length; i++)
		{
			MLandedCostAllocation lca = lcas[i];
			if (lca.getBase().signum() == 0)
				continue;
			double percent = lca.getBase().doubleValue() / totalBase;
			String desc = il.getDescription();
			if (desc == null)
				desc = percent + "%";
			else
				desc += " - " + percent + "%";
			if (line.getDescription() != null)
				desc += " - " + line.getDescription(); 
			
			//	Accounting
			ProductCost pc = new ProductCost (Env.getCtx(), 
				lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(), getTrxName());
			BigDecimal drAmt = null;
			BigDecimal crAmt = null;
			if (dr)
				drAmt = lca.getAmt();
			else
				crAmt = lca.getAmt();
			FactLine fl = fact.createLine (line, pc.getAccount(ProductCost.ACCTTYPE_P_CostAdjustment, as),
				getC_Currency_ID(), drAmt, crAmt);
			fl.setDescription(desc);
			fl.setM_Product_ID(lca.getM_Product_ID());
			
			//	Cost Detail - Convert to AcctCurrency
			BigDecimal allocationAmt =  lca.getAmt();
			if (getC_Currency_ID() != as.getC_Currency_ID())
				allocationAmt = MConversionRate.convert(getCtx(), allocationAmt, 
					getC_Currency_ID(), as.getC_Currency_ID(),
					getDateAcct(), getC_ConversionType_ID(), 
					getAD_Client_ID(), getAD_Org_ID());
			if (allocationAmt.scale() > as.getCostingPrecision())
				allocationAmt = allocationAmt.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
			if (!dr)
				allocationAmt = allocationAmt.negate();
			// AZ Goodwill
			// use createInvoice to create/update non Material Cost Detail
			MCostDetail.createInvoice(as, lca.getAD_Org_ID(), 
					lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(),
					C_InvoiceLine_ID, lca.getM_CostElement_ID(),
					allocationAmt, lca.getQty(),
					desc, getTrxName());
			// end AZ
		}
		
		log.config("Created #" + lcas.length);
		return true;
	}	//	landedCosts

//	/**
//	 * 	Update ProductPO PriceLastInv
//	 *	@param as accounting schema
//	 */
//	private void updateProductPO (MAcctSchema as)
//	{
//		MClientInfo ci = MClientInfo.get(getCtx(), as.getAD_Client_ID());
//		if (ci.getC_AcctSchema1_ID() != as.getC_AcctSchema_ID())
//			return;
//		
//		StringBuffer sql = new StringBuffer (
//			"UPDATE M_Product_PO po "
//			+ "SET PriceLastInv = "
//			//	select
//			+ "(SELECT currencyConvert(il.PriceActual,i.C_Currency_ID,po.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID) "
//			+ "FROM C_Invoice i, C_InvoiceLine il "
//			+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
//			+ " AND po.M_Product_ID=il.M_Product_ID AND po.C_BPartner_ID=i.C_BPartner_ID");
//			//jz + " AND ROWNUM=1 AND i.C_Invoice_ID=").append(get_ID()).append(") ")
//			if (DB.isOracle()) //jz
//			{
//				sql.append(" AND ROWNUM=1 ");
//			}
//			else 
//			{
//				sql.append(" AND il.C_InvoiceLine_ID = (SELECT MIN(il1.C_InvoiceLine_ID) "
//						+ "FROM C_Invoice i1, C_InvoiceLine il1 "
//						+ "WHERE i1.C_Invoice_ID=il1.C_Invoice_ID"
//						+ " AND po.M_Product_ID=il1.M_Product_ID AND po.C_BPartner_ID=i1.C_BPartner_ID")
//						.append("  AND i1.C_Invoice_ID=").append(get_ID()).append(") ");
//			}
//			sql.append("  AND i.C_Invoice_ID=").append(get_ID()).append(") ")
//			//	update
//			.append("WHERE EXISTS (SELECT * "
//			+ "FROM C_Invoice i, C_InvoiceLine il "
//			+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
//			+ " AND po.M_Product_ID=il.M_Product_ID AND po.C_BPartner_ID=i.C_BPartner_ID"
//			+ " AND i.C_Invoice_ID=").append(get_ID()).append(")");
//		int no = DB.executeUpdate(sql.toString(), getTrxName());
//		log.fine("Updated=" + no);
//	}	//	updateProductPO
	
//	/**
//	 *  Update Product Info (old).
//	 *  - Costing (PriceLastInv)
//	 *  - PO (PriceLastInv)
//	 *  @param C_AcctSchema_ID accounting schema
//	 *  @deprecated old costing
//	 */
//	private void updateProductInfo (int C_AcctSchema_ID)
//	{
//		log.fine("C_Invoice_ID=" + get_ID());
//
//		/** @todo Last.. would need to compare document/last updated date
//		 *  would need to maintain LastPriceUpdateDate on _PO and _Costing */
//
//		//  update Product Costing
//		//  requires existence of currency conversion !!
//		//  if there are multiple lines of the same product last price uses first
//		//	-> TotalInvAmt is sometimes NULL !! -> error
//		// begin globalqss 2005-10-19
//		// postgresql doesn't support LIMIT on UPDATE or DELETE statements
//		/*
//		StringBuffer sql = new StringBuffer (
//			"UPDATE M_Product_Costing pc "
//			+ "SET (PriceLastInv, TotalInvAmt,TotalInvQty) = "
//			//	select
//			+ "(SELECT currencyConvert(il.PriceActual,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID),"
//			+ " currencyConvert(il.LineNetAmt,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID),il.QtyInvoiced "
//			+ "FROM C_Invoice i, C_InvoiceLine il, C_AcctSchema a "
//			+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
//			+ " AND pc.M_Product_ID=il.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
//			+ " AND ROWNUM=1"
//			+ " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND i.C_Invoice_ID=")
//			.append(get_ID()).append(") ")
//			//	update
//			.append("WHERE EXISTS (SELECT * "
//			+ "FROM C_Invoice i, C_InvoiceLine il, C_AcctSchema a "
//			+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
//			+ " AND pc.M_Product_ID=il.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
//			+ " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND i.C_Invoice_ID=")
//				.append(get_ID()).append(")");
//		*/
//		// the next command is equivalent and works in postgresql and oracle
//		StringBuffer sql = new StringBuffer (
//				"UPDATE M_Product_Costing pc "
//				+ "SET (PriceLastInv, TotalInvAmt,TotalInvQty) = "
//				//	select
//				+ "(SELECT currencyConvert(il.PriceActual,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID),"
//				+ " currencyConvert(il.LineNetAmt,i.C_Currency_ID,a.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID),il.QtyInvoiced "
//				+ "FROM C_Invoice i, C_InvoiceLine il, C_AcctSchema a "
//				+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
//				+ " AND il.c_invoiceline_id = (SELECT MIN(C_InvoiceLine_ID) FROM C_InvoiceLine il2" +
//						" WHERE  il2.M_PRODUCT_ID=il.M_PRODUCT_ID AND C_Invoice_ID=")
//				.append(get_ID()).append(")"
//				+ " AND pc.M_Product_ID=il.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
//				+ " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND i.C_Invoice_ID=")
//				.append(get_ID()).append(") ")
//				//	update
//				.append("WHERE EXISTS (SELECT * "
//				+ "FROM C_Invoice i, C_InvoiceLine il, C_AcctSchema a "
//				+ "WHERE i.C_Invoice_ID=il.C_Invoice_ID"
//				+ " AND pc.M_Product_ID=il.M_Product_ID AND pc.C_AcctSchema_ID=a.C_AcctSchema_ID"
//				+ " AND pc.C_AcctSchema_ID=").append(C_AcctSchema_ID).append(" AND i.C_Invoice_ID=")
//					.append(get_ID()).append(")");
//		// end globalqss 2005-10-19
//		int no = DB.executeUpdate(sql.toString(), getTrxName());
//		log.fine("M_Product_Costing - Updated=" + no);
//	}   //  updateProductInfo
	
//	private void createFactsAsset(MAcctSchema as, Fact fact)
//	{
//		
//		StringBuffer sql = new StringBuffer();
//		//  ** ARI, ARF
//		if (getDocumentType().equals(DOCTYPE_ARInvoice) 
//			|| getDocumentType().equals(DOCTYPE_ARProForma))
//		{
//			MDocType dt = MDocType.get (getCtx(), 
//					  p_po.get_ValueAsInt("C_DocTypeTarget_ID"));
//			String sDocName = dt.getName();		
//			/* ++++++++++++++++++++++++++++++++ Asset Out +++++++++++++++++*/ 
//			for (int i = 0; i < p_lines.length; i++)
//			{
//
//				DocLine line = p_lines[i];
//				if (line.getA_Asset_ID() > 0) 
//				{
//					X_A_Asset asset = new X_A_Asset (getCtx(), line.getA_Asset_ID(), getTrxName());
//					BigDecimal bAssetCost = asset.getAssetCost(getDateAcct());
//					BigDecimal bAccumDep = asset.getAccumDepreciation(getDateAcct());
//					BigDecimal bBal = bAssetCost.subtract(bAccumDep);
//					int no=0;
//					if (bAssetCost != null && bAssetCost.signum() != 0) {
//						sql.setLength(0);
//						sql.append("SELECT A_Asset_Acct FROM A_Asset_Acct "
//							 + " WHERE A_Asset_ID = "+ line.getA_Asset_ID()); 
//						no = DB.getSQLValue(getTrxName(), sql.toString());
//						if (no>0) {
//							MAccount acct = MAccount.get (as.getCtx(), no);
//							fact.createLine(line, acct, getC_Currency_ID(), null, 
//			    			 bAssetCost);
//						}
//						sql.setLength(0);    
//						sql.append("SELECT A_Accumdepreciation_Acct FROM A_Asset_Acct "
//								+ " WHERE A_Asset_ID = "+ line.getA_Asset_ID()); 
//						no = DB.getSQLValue(getTrxName(), sql.toString());
//						if (no>0) {
//							if (bAccumDep != null && bAccumDep.signum() != 0
//								&&	(!"ARI (Capital)".equals(sDocName))	) {
//								MAccount acct = MAccount.get (as.getCtx(), no);
//								fact.createLine(line, acct, getC_Currency_ID(), bAccumDep, null);
//							}	
//						}
//				    }
//
//				    sql.setLength(0);    
//					sql.append("SELECT A_Disposal_Loss FROM A_Asset_Acct "
//						 + " WHERE A_Asset_ID = "+ line.getA_Asset_ID()); 
//				    no = DB.getSQLValue(getTrxName(), sql.toString());
//					if ("ARI (Capital)".equals(sDocName)) {
//						no = as.getAcctSchemaDefault().getWithholding_Acct();
//						bBal=bAssetCost;
//					}
//				    
//				    if (no>0) {
//				    	fact.createLine(line, MAccount.get (as.getCtx(), no), getC_Currency_ID(),  
//				    			bBal, null);
//				    }
//			    	asset.setAssetDisposalDate(getDateAcct());
//			    	asset.setIsDisposed(true);
//			    	// Adding info for Asset Card
//			    	asset.save(); 
//			    	// Adding Asset Posting
//			    	sql.setLength(0);
//			    	sql.append("SELECT A_Asset_Addition_ID FROM A_Asset_Addition "
//						 + " WHERE C_InvoiceLine_id = "+ line.get_ID());
//			    	no = 0;
//			    	no = DB.getSQLValue(getTrxName(), sql.toString());
//			    	X_A_Asset_Addition assetadd = new X_A_Asset_Addition (getCtx(), no, getTrxName());
//			    	assetadd.setAD_Org_ID(line.getAD_Org_ID());
//			    	assetadd.setA_Asset_ID(line.getA_Asset_ID());
//			    	assetadd.setAssetValueAmt(bAssetCost.negate());
//			    	assetadd.setAssetDepAmt(bAccumDep.negate());
//			    	assetadd.setA_SourceType("INV");
//			    	assetadd.setA_CapvsExp("Exp");
//			    	assetadd.setM_InOutLine_ID(line.getLine());				
//			    	assetadd.setC_Invoice_ID(get_ID());
//			    	assetadd.setC_InvoiceLine_ID(line.get_ID());
//			    	assetadd.setLine(line.getLine());
//			    	assetadd.setDescription(line.getDescription());
//			    	assetadd.setA_QTY_Current(line.getQty());
//			    	assetadd.setPostingType("A");
//			    	assetadd.setDateAcct(line.getDateAcct());
//			    	assetadd.save();
//				
//			    	// Adding Asset Balances
//			    	sql.setLength(0);
//			    	sql = new StringBuffer ("SELECT A_Depreciation_Workfile_ID FROM A_Depreciation_Workfile "
//						 + " WHERE PostingType = 'A' "+
//						 " AND A_Asset_ID = "+ line.getA_Asset_ID()); 
//			    	no = DB.getSQLValue(getTrxName(), sql.toString());
//			    	MDepreciationWorkfile assetblc = new MDepreciationWorkfile (getCtx(), no, getTrxName());
//			    	assetblc.setAD_Org_ID(line.getAD_Org_ID());
//			    	assetblc.setA_Asset_ID(line.getA_Asset_ID());
//			    	assetblc.setPostingType("A");
//			    	assetblc.setA_Asset_Cost(BigDecimal.ZERO);
//			    	assetblc.setA_Accumulated_Depr(BigDecimal.ZERO);
//			    	assetblc.setA_Depreciated_Cost(BigDecimal.ZERO);
//			    	assetblc.save();
//				}
//			}	
//		}
/* -------------------------------- Asset Out -----------------*/ 
//	}
	
	@Override
	public int getC_Currency_ID() {
		int result = super.getC_Currency_ID();
		if (result <= 0) {
			int AD_Client_ID =  Env.getAD_Client_ID(getCtx());
		    MAcctSchema[] acctSchema = MAcctSchema.getClientAcctSchema(getCtx(), AD_Client_ID, getTrxName());
		    for(MAcctSchema as: acctSchema) {
		    	if (as.isActive()) { //TODO определить актуальную схему по клиенту!
		    		result = as.getC_Currency_ID();
		    	}
		    }
		}
		return result;
	}

	/**
	 * @param vac
	 * @param as
	 * @return
	 */
	private ArrayList<Fact> makeCorrectFact(Mhrmreview rev, MAcctSchema as) {
		ArrayList<Fact> facts = new ArrayList<Fact>();

		int Reversal_ID = rev.getReversal_ID();
		Mhrmreview reversal = new Mhrmreview(getCtx(),Reversal_ID,rev.get_TrxName());
		
		String sql = "SELECT * FROM hrm_review WHERE hrm_review_id = ?";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try{
			pstmt = DB.prepareStatement(sql, null);
			pstmt.setInt(1, rev.gethrm_review_ID());
			rs = pstmt.executeQuery();
			if (rs != null) {
				MAcctSchema[] ass = as.getClientAcctSchema(getCtx(), Env.getAD_Client_ID(getCtx()));
				Doc_hrmreview reversalDoc = (Doc_hrmreview) Doc.get(ass, MTable.getTable_ID(reversal.get_TableName()), reversal.gethrm_review_ID(), getTrxName());
				
				String sql1 = "SELECT * FROM Fact_Acct \n"
						    + "WHERE AD_Org_ID = ? \n"
						    + "  AND AD_Client_ID = ? \n"
						    + "  AND AD_Table_ID = ? \n"
						    + "  AND Record_ID = ? \n "
						    + "  AND PostingType = ? \n";
				int temp_AD_Org_ID = reversalDoc.getAD_Org_ID();
				int temp_AD_Cleint_ID = reversalDoc.getAD_Client_ID();
				int temp_AD_Table_ID = MTable.getTable_ID(rev.get_TableName());
				int temp_Record_ID = Reversal_ID;
				String temp_PostingType = Fact.POST_Actual; 
				PreparedStatement pstmt1 = null;
				ResultSet rs1 = null;
				Fact fact = new Fact(this, as, Fact.POST_Actual);
				try {
					pstmt1 = DB.prepareStatement(sql1, rev.get_TrxName());
					pstmt1.setInt(1, temp_AD_Cleint_ID);
					pstmt1.setInt(2, temp_AD_Org_ID);
					pstmt1.setInt(3, temp_AD_Table_ID);
					pstmt1.setInt(4, temp_Record_ID);
					pstmt1.setString(5, temp_PostingType);
					rs1 = pstmt1.executeQuery();
					while(rs1.next()) {
						MFactAcct fa = new MFactAcct(Env.getCtx(),rs1,rev.get_TrxName());
						MAccount account = getAccount(fa,as); // TODO 
						FactLine fl = fact.createLine(null, account,fa.getC_Currency_ID(), fa.getAmtAcctDr().negate(), fa.getAmtAcctCr().negate());
					}
				} catch(SQLException e) {
					log.log(Level.WARNING, e.getLocalizedMessage());
				} finally {
					DB.close(rs1, pstmt1);
					rs1 =null;
					pstmt1 = null;
				}
				facts.add(fact);
			}
		} catch(SQLException e) {
			log.log(Level.WARNING, e.getLocalizedMessage());
		} finally {
			DB.close(rs, pstmt);
			rs =null;
			pstmt = null;
		}
		
		return facts;
	}

	private MAccount getAccount(MFactAcct fa,	MAcctSchema as) {
		//TODO Сделать под общий вариант!
		MAccount result = null;
		
		MAccount acct7210 = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as); //7210
		MAccount acct3120 = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
		MAccount acct3150 = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
		MAccount acct3210 = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
		MAccount acct3220 = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
		MAccount acct3350 = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
		MAccount acct3430 = getAccount(Doc.ACCTTYPE_HRMREZERV, as); //3430
		if (acct7210.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct7210; 
		} else if (acct3120.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3120; 
		} else if (acct3150.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3150; 
		} else if (acct3210.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3210; 
		} else if (acct3220.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3220; 
		} else if (acct3350.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3350; 
		} else if (acct3430.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3430; 
		}
		return result;
	}
	
}   //  Doc_HRM
